package storage;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;

import javax.swing.JOptionPane;

import org.jdom.Element;

import data.ConfigInfo;
import data.FilePath;

import fileIO.XMLParser;

import profileEditor.ProfileEditor;
import profileEditor.RuleEditor;

/**
 * Reads a file which determines the mapping of fields to data
 * @author Jonathan Chuang
 */
public class ExceptionInfo {
	private static Hashtable<String,Field> fieldTable; //<Field, Column in excel>
	private static Hashtable<String,Field> allFieldsTable; 
	private static ArrayList<String> numericalKeys;
	private static ArrayList<String> textKeys;
	private static int titleRow;
	private static int cneeColumnNo;
	private static int originColumnNo;
	
	public static void initialize(){
		fieldTable = new Hashtable<String, Field>();
		allFieldsTable = new Hashtable<String, Field>();
		numericalKeys = new ArrayList<String>();
		textKeys = new ArrayList<String>();
		titleRow = -1;
		cneeColumnNo = -1;
		originColumnNo = -1;
		String configMapping = "";
		if(ConfigInfo.LAST_USED_MAPPING.length()>0){
			configMapping = ConfigInfo.LAST_USED_MAPPING;
		}else{
			//Since no other field mappings are allowed, we'll default to test.map
			configMapping = "default.map";
			//create new file "default.map"
			File defaultMap = new File(FilePath.FIELD_COLUMN_MAPPING_DIRECTORY + configMapping);
			if(!defaultMap.exists()){
				//If default file does not exist
				try {
					defaultMap.createNewFile();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		File f = new File(FilePath.FIELD_COLUMN_MAPPING_DIRECTORY + configMapping);
		if(f.exists()){
			parseFieldColumnTable(f.getAbsolutePath());
		}else{
			ConfigInfo.LAST_USED_MAPPING = "";
		}
	}
	public static int getTitleRow(){
		return titleRow;
	}
	public static int getOriginColumnNo(){
		return originColumnNo;
	}
	public static void updateFields(){
		RuleEditor.updateFields();
		ProfileEditor.updateFields();
	}
	public static void parseFieldColumnTable(String filePath){
		Element root = XMLParser.parseDocument(filePath);
		
		if(root!=null){
			//Clear all previous mappings
			allFieldsTable.clear();
			fieldTable.clear();
			numericalKeys.clear();
			textKeys.clear();
			titleRow = -1;
			cneeColumnNo = -1;
			originColumnNo = -1;
			
			Object[] childList = root.getChildren().toArray();
			boolean cneeFound = false;
			boolean originFound = false;
			
			for(int i=0;i<childList.length;i++){
				Element currElement = (Element)childList[i];
				String name = currElement.getName();
				if(name.equals("Field")){
					Element nameNode = currElement.getChild("Name");
					Element columnNode = currElement.getChild("Column");
					Element typeNode = currElement.getChild("Type");
					Element originNode = currElement.getChild("Origin");
					Element exceptionNode = currElement.getChild("Exception");
					
					try{
						//Add fields to collections where appropriate
						Field field = new Field(nameNode.getText(),Integer.parseInt(columnNode.getText()),typeNode.getText(),new Boolean(originNode.getValue()),new Boolean(exceptionNode.getValue()));
						if(allFieldsTable.containsKey(field.name)){
							int selection = JOptionPane.showConfirmDialog(null, "Duplicate field " + nameNode.getText() + " found!  Press YES to skip, NO to terminate", "Duplicate Field",JOptionPane.YES_NO_OPTION);
							switch(selection){
							case JOptionPane.YES_OPTION:
								continue;
							case JOptionPane.NO_OPTION:
								System.exit(0);
							}
						}else{
							allFieldsTable.put(field.name, field);
							if(!field.type.equals("CNEE")&&(!field.type.equals("ORIGIN"))){
								fieldTable.put(field.name,field);
								if(field.type.equals("DATE")){
									numericalKeys.add(field.name);
								}else if(field.type.equals("STRING")){
									textKeys.add(field.name);
								}
							}else if(field.type.equals("CNEE")){
								if(!cneeFound){
									cneeColumnNo = Integer.parseInt(columnNode.getText());
									cneeFound = true;
								}else{
									//duplicate column designated key
									JOptionPane.showMessageDialog(null,"Multiple CNEE field types found! Duplicate CNEE field not added");
								}
							}else if(field.type.equals("ORIGIN")){
								if(!originFound){
									originColumnNo = Integer.parseInt(columnNode.getText());
									originFound = true;
								}else{
									//duplicate column designated key
									JOptionPane.showMessageDialog(null,"Multiple Origin field types found! Duplicate Origin field not added");
								}
							}
						}
					}catch(NumberFormatException e){
						JOptionPane.showMessageDialog(null,"Column number could not be read for field: "+ nameNode.getText());
						System.exit(0);
					}
				//Get Title row if found
				}else if(name.equals("Title")){
					String title = currElement.getText();
					try{
						titleRow = Integer.parseInt(title);
					}catch(NumberFormatException e){
						int selection = JOptionPane.showConfirmDialog(null, "Title row number cannot be parsed! Continue?", "Title Row Error in XML", JOptionPane.YES_NO_OPTION);
						switch(selection){
						case JOptionPane.NO_OPTION:
							System.exit(0);
						case JOptionPane.YES_OPTION:
							titleRow = -1;
							break;
						}
					}
				}
			}
		}
	}
	public static String getFieldType(String name){
		if(name.equals("TODAY")){
			return "DATE";
		}
		return allFieldsTable.get(name).type;
	}
	
	public static Object[] getAllFieldNames(){
		return allFieldsTable.keySet().toArray();
	}
	public static Object[] getFieldNames(){
		Object[] passed = fieldTable.keySet().toArray();
		return passed;
	}
	public static Object[] getNumericalFieldNames(){
		return numericalKeys.toArray();
	}
	public static Object[] getTextFieldNames(){
		return textKeys.toArray();
	}
	public static int getCneeColumn(){
		return cneeColumnNo;
	}
	public static int getOriginColumn(){
		return originColumnNo;
	}
	public static Field getField(String name){
		return allFieldsTable.get(name);
	}
}
